package com.small.nine.wxmp.domain.bean.wx.qrCode;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.small.nine.wxmp.common.JsonService;
import com.small.nine.wxmp.utils.wx.JsonUtils;
import lombok.Data;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 生成 二维码 所需参数
 *
 * @author sheng_zs@126.com
 * @date 2021-08-11 16:13
 */
@Data
public class WxQrCodeBean implements JsonService {
    private static final long serialVersionUID = 8130859762251867587L;

    /**
     * 该二维码有效时间，以秒为单位。 最大不超过 2592000（即30天）<br>
     * 此字段如果不填，则默认有效期为30秒。
     */
    @JsonProperty("expire_seconds")
    private Integer expireSeconds;

    /**
     * 二维码类型
     * <ol>
     *  <li>QR_SCENE为临时的整型参数值</li>
     *  <li>QR_STR_SCENE为临时的字符串参数值</li>
     *  <li>QR_LIMIT_SCENE为永久的整型参数值</li>
     *  <li>QR_LIMIT_STR_SCENE为永久的字符串参数值</li>
     * </ol>
     */
    @JsonProperty("action_name")
    private String actionName;

    /**
     * 二维码详细信息
     */
    @JsonProperty("action_info")
    private ActionInfo actionInfo;

    /**
     * 初始化，获取 scene_str 对象
     *
     * @param isTemporary   是否是临时二维码
     * @param sceneId       场景值ID，临时二维码时为32位非0整型，永久二维码时最大值为100000（目前参数只支持1--100000）
     * @param expireSeconds 过期时间，最大不超过 2592000，如果不是临时二维码，则要求为 null
     * @return {@link WxQrCodeBean}
     */
    public static WxQrCodeBean getSceneIdInstance(boolean isTemporary, Integer sceneId, Integer expireSeconds) {
        // 参数判断
        final boolean flag =
                (isTemporary && ((Objects.isNull(expireSeconds) || expireSeconds > 2592000 || expireSeconds <= 0)))
                        || (!isTemporary && (Objects.nonNull(expireSeconds) || sceneId > 100000 || sceneId < 1));
        if (flag) {
            throw new IllegalArgumentException("生成二维码参数有误！");
        }
        WxQrCodeBean codeBean = new WxQrCodeBean();
        codeBean.setExpireSeconds(expireSeconds);
        codeBean.setActionName(isTemporary ? "QR_SCENE" : "QR_LIMIT_SCENE");
        codeBean.setActionInfo(ActionInfo.getSceneId(sceneId));
        return codeBean;
    }

    /**
     * 初始化，获取 scene_str 对象
     *
     * @param isTemporary   是否是临时二维码
     * @param sceneStr      场景值ID（字符串形式的ID），字符串类型，长度限制为1到64
     * @param expireSeconds 过期时间，最大不超过 2592000，如果不是临时二维码，则要求为 null
     * @return {@link WxQrCodeBean}
     */
    public static WxQrCodeBean getSceneStrInstance(boolean isTemporary, String sceneStr, Integer expireSeconds) {
        // 参数判断
        final boolean flag =
                (isTemporary && (Objects.isNull(expireSeconds) || expireSeconds > 2592000 || expireSeconds <= 0))
                        || (!isTemporary && Objects.nonNull(expireSeconds)) || StrUtil.isBlank(sceneStr);
        if (flag) {
            throw new IllegalArgumentException("生成二维码参数有误！");
        }
        WxQrCodeBean codeBean = new WxQrCodeBean();
        codeBean.setExpireSeconds(expireSeconds);
        codeBean.setActionName(isTemporary ? "QR_STR_SCENE" : "QR_LIMIT_STR_SCENE");
        codeBean.setActionInfo(ActionInfo.getSceneStr(sceneStr));
        return codeBean;
    }

    @Override
    public String toJson() {
        return JsonUtils.writeValueAsString(this);
    }

    @Data
    static class ActionInfo implements Serializable {
        private static final long serialVersionUID = 7991920827813927331L;

        /**
         * scene
         */
        private Map<String, Object> scene;

        /**
         * 初始化，获取 scene_id 对象
         *
         * @param sceneId scene_id
         * @return {@link ActionInfo}
         */
        static ActionInfo getSceneId(Integer sceneId) {
            ActionInfo info = new ActionInfo();
            Map<String, Object> map = new HashMap<>(1);
            map.put("scene_id", sceneId);
            info.setScene(map);
            return info;
        }

        /**
         * 初始化，获取 scene_str 对象
         *
         * @param sceneStr scene_str
         * @return {@link ActionInfo}
         */
        static ActionInfo getSceneStr(String sceneStr) {
            ActionInfo info = new ActionInfo();
            Map<String, Object> map = new HashMap<>(1);
            map.put("scene_str", sceneStr);
            info.setScene(map);
            return info;
        }
    }
}
